<?php

namespace app\course\logic\payment;

use app\common\exception\LogicException;
use app\common\helper\util\SnowFlake;
use app\common\logic\{CreditRedeem, Transaction};
use app\common\model\{ProductType, ShareCode};
use app\course\logic\base\{Course, CourseSection, CourseStudent};
use app\course\logic\classes\Classes;
use app\course\logic\coupon\{Coupon, CouponUser};
use app\course\model\base\CourseCart;
use app\course\model\payment\{PaymentOrder as PaymentOrderModel,
    PaymentOrderItem as POI,
    PaymentOrderItemCoupon as POIC
};
use app\promotion\logic\{PromotionTuan as PT, PromotionTuanData as PTD};
use app\user\logic\user\{Account as User, Credit, ExpenditureFlow, VipUser};
use app\user\model\user\TicketCoupon;
use Exception;
use Generator;
use think\facade\{Db, Request};
use think\response\Json;

/**
 * 订单逻辑类
 * @method Join(string $string, string $string1)
 */
class PaymentOrder extends PaymentOrderModel
{

    protected $couponField;
    protected $orderField;
    protected $close_time;
    protected $from;
    protected $uid;

    public function __construct()
    {
        parent::__construct();
        $this->uid         = request()->mid;
        $this->from        = strtolower(request()->device_type);
        $this->couponField = 'id,price,vip_price,credit_redeem,credit_redeem_percent';
        $this->orderField  = 'id,cover,title,price,vip_price,term_time,solo,mhm_id,limit_buy_count,course_type,credit_redeem,credit_redeem_percent';
        $this->close_time  = 0;//time() + 30 * 60;// 订单有效期，后期查后台配置
    }

    /* 课程直接购买 */

    /**
     * 直接购买订单页
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     */
    public function orderCourseFetch($param)
    {
        // 验证数据
        $this->getValidate()->scene('course_fetch')->failException()->check($param);
        // 参数
        $course_id = intval($param['course_id']);
        $promotion = intval($param['promotion_id'] ?? 0);
        $append    = ['course_type_text', 'user_price'];
        $promotion && array_push($append, 'positive_promotion');

        $course = app(Course::class)->field($this->orderField)->with(['cover_url'])->withCount(['section_count' => 'section_count'])->findOrFail($course_id)->append($append);
        // 非单卖课程禁止购买
        if (!$course->solo) throw new LogicException('课程禁止购买');
        if ($course->term_time && strlen($course->term_time . '') > 4 && $course->term_time < time()) {
            throw new LogicException('课程已失效');
        }
        //
        $course->promotion_type      = 0;
        $course->promotion_type_text = '';
        if ($promotion) {
            if ($course->positive_promotion['id'] != $promotion) throw new LogicException('活动参数错误');

            $course->promotion_type      = $course->positive_promotion['type'] ?? 0;
            $course->promotion_type_text = $course->positive_promotion['type_text'] ?? '';
        }
        //
        $price = $promotion ? $course->positive_promotion['price'] ?? 0 : $course->user_price;
        $price = min($price, $course->user_price);
        // 积分抵扣数组
        $course->credit_arr = [];
        if ($course->credit_redeem) {
            $max_price          = bcmul($price, bcdiv($course->credit_redeem_percent, 100, 2), 2);
            $course->credit_arr = app(Credit::class)->getUserCreditRedeemArr($max_price, $price);
        }
        // 班级课处理
        if ($course->course_type == 4) {
            $course->section_count = app(Classes::class)->getClassesSectionCount($course->id);
        }

        return $course;
    }

    /**
     * 切换卡券更新积分选择
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-08-30
     *
     * @param  [type] $param [description]
     */
    public function orderCourseCredit($param): array
    {
        // 验证数据
        $this->getValidate()->scene('course_credit')->failException()->check($param);
        // 参数
        $course_id = intval($param['course_id']);
        $promotion = intval($param['promotion_id'] ?? 0);
        $coupon_id = intval($param['coupon_id'] ?? 0);
        $ticket_id = intval($param['ticket_id'] ?? 0);
        $append    = ['user_price'];
        $promotion && array_push($append, 'positive_promotion');

        $course = app(Course::class)->field($this->orderField)->findOrFail($course_id);
        $price  = $course->user_price;
        //
        $course->promotion_type      = 0;
        $course->promotion_type_text = '';
        if ($promotion) {
            if ($course->positive_promotion['id'] != $promotion) throw new LogicException('活动参数错误');

            $course->promotion_type      = $course->positive_promotion['type'] ?? 0;
            $course->promotion_type_text = $course->positive_promotion['type_text'] ?? '';
            //
            $price = $course->positive_promotion['price'] ?: $course->final_price;
        }
        // else
        if ($coupon_id) {
            //
            $coupon = app(Coupon::class)->with(['user_has'])->findOrEmpty($coupon_id);
            //
            if ($coupon->isEmpty() || !$coupon->user_has) throw new LogicException('卡券异常，请更换使用');
            // 计算总共优惠的价格
            switch ($coupon->coupon_type) {
                case 1:
                    if ($price < $coupon->maxprice) throw new LogicException('订单价格不满足卡券使用条件');
                    $price = bcsub($price, $coupon->price, 2);
                    break;
                case 2:
                    $price = bcmul(bcdiv($coupon->discount, 10, 3), $price, 2);
                    break;
                case 3:
                    $price = '0';
                    break;
            }
        } else if ($ticket_id) {
            //
            $coupon = app(TicketCoupon::class)->with(['user_has'])->findOrEmpty($ticket_id);
            //
            if ($coupon->isEmpty() || !$coupon->user_has) throw new LogicException('卡券异常，请更换使用');
            // 计算总共优惠的价格
            switch ($coupon->coupon_type) {
                case 1:
                    if ($price < $coupon->maxprice) throw new LogicException('订单价格不满足卡券使用条件');
                    $price = bcsub($price, $coupon->price, 2);
                    break;
                case 2:
                    $price = bcmul(bcdiv($coupon->discount, 10, 3), $price, 2);
                    break;
            }
        }

        // 积分抵扣数组
        $credit_arr = [];
        if ($course->credit_redeem) {
            $max_price  = bcdiv(bcmul($price, $course->credit_redeem_percent, 2), '100');
            $credit_arr = app(Credit::class)->getUserCreditRedeemArr($max_price, $price);
        }

        return $credit_arr;
    }

    /**
     * 创建课程订单
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-24
     */
    public function createCourseOrder($param)
    {
        // 事件检测 用户--课程--卡券对应关系是否正确，及卡券使用情况
        // 【用户是否具有此卡、满减情况、折扣金额情况】

        // 验证数据
        $this->getValidate()->scene('course_order')->failException()->check($param);
        // 参数
        $course_id = $param['course_id'];
        $coupon_id = intval($param['coupon_id'] ?? 0);
        $ticket_id = intval($param['ticket_id'] ?? 0);
        $promotion = intval($param['promotion_id'] ?? 0);
        $credit    = $param['credit'] ?? [];
        $credit    = is_array($credit) ? $credit : json_decode($credit, true);
        $append    = ['course_type_text', 'user_price'];
        $promotion && array_push($append, 'positive_promotion');
        // 数据 -- 根据机构分别查询课程信息
        $datas = [];
        // 课程列表信息 - 为统一使用calculatePrice方法，此处需要使用select查询
        $list = app(Course::class)->where('id', $course_id)->field($this->orderField)->selectOrFail()->append($append);

        if ($list->isEmpty()) throw new LogicException('数据错误', '未查询到数据');

        $this->startTrans();
        try {
            $course_num = count($list);
            // 重复订单、小班课、免费课处理
            foreach ($list as $k => $l) {
                $pp             = $l['positive_promotion'];
                $l->final_price = $l->user_price;
                // 拼团、砍价时效
                if ($promotion && count($pp)) {
                    $l['promotion']      = $pp['id'];
                    $l['promotion_type'] = $pp['type'];
                    switch ($pp['type']) {
                        case 4:
                            $this->close_time = min($pp['end_time'], $pp['expiry_time']);
                            break;

                        default:
                            $this->close_time = $pp['end_time'];
                            break;
                    }
                    $l->final_price = min($l->user_price, $pp['price']);
                }
                // 检查重复订单
                $this->checkOrderExist($l['id'], $l['course_type']);
                // 小班课人数限制检测
                $this->checkSmallLiveLimit($l);
                // 剔除免费课程 - 单课程一般不会走这里，此处作逻辑的缜密性
                if ($l['user_price'] == 0) {
                    $this->handleFreeCourse($l);
                    $course_num -= 1;
                    if (!$course_num) throw new LogicException('课程不需要购买');
                    unset($list[$k]);
                }
            }
            // 可使用卡券
            $coupon = [];
            if ($coupon_id) {
                $coupon = app(Coupon::class)->with(['user_has_unused'])->findOrEmpty($coupon_id);
                if ($coupon->isEmpty() || !$coupon->user_has) throw new LogicException('卡券异常，请更换使用');
                $coupon = $coupon->hidden(['user_has_unused'])->toArray();
            } else if ($ticket_id) {
                $coupon = app(TicketCoupon::class)->with(['user_has_unused'])->findOrEmpty($ticket_id);
                if ($coupon->isEmpty() || !$coupon->user_has) throw new LogicException('卡券异常，请更换使用');
                $coupon = $coupon->hidden(['user_has_unused'])->toArray();
            }

            // 计算价格后的数据列表
            $datas = $this->calculatePrice($list, $coupon, $datas);
            // 检查积分抵扣是否符合
            $datas = $this->checkCreditRedeem($datas, $credit);
            // 检查价格
            $course_price = round(array_sum(array_column($datas, 'payment')), 2);
            // 生成订单
            $order = $this->createOrder($datas, $course_price);
            // 抵扣积分
            if (count($credit) && isset($credit['credit']) && $credit['credit']) {
                app(Credit::class)->redeemCredit($credit['credit'], $order->order_no);
            }
            $this->commit();
            return $order;
        } catch (LogicException|Exception $e) {
            $this->rollback();
            throw new LogicException($e->getMessage());
        }
    }

    /**
     * 积分抵扣并返回数据
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-08-26
     */
    public function checkCreditRedeem($datas, $credit)
    {
        // 定义是否存在课程可以抵扣积分
        // $credit_redeem = 0;
        // 定义可以抵扣积分课程的抵扣价格总和
        $max_price = 0;
        //
        foreach ($datas as &$l) {
            if ($l['credit_redeem']) {
                // $credit_redeem    = 1;
                $l['can_rdm_max'] = bcmul($l['payment'], bcdiv($l['cdt_rdm_per'], 100, 2), 2);
                $max_price        = bcadd($l['can_rdm_max'], $max_price, 2);
            }
        }
        unset($l);
        //
        if (!count($credit) || !isset($credit['credit']) || !isset($credit['num'])) return $datas;
        //
        if ($credit['num'] > $max_price) throw new LogicException('积分抵扣参数错误');
        //
        $count      = count($datas);
        $add_num    = 0;
        $add_credit = 0;

        foreach ($datas as $k => &$l) {
            //
            if (!$l['credit_redeem']) continue;
            //
            if ($count != 1 && $count - 1 == $k) {
                $rdm_num    = bcsub($credit['num'], $add_num, 2);
                $rdm_credit = bcsub($credit['credit'], $add_credit, 2);

                $l['payment'] = bcsub($l['payment'], $rdm_num, 2);
                $l['credit']  = ['credit' => $rdm_credit, 'num' => $rdm_num];
            } else {
                $rdm_num    = round($credit['num'] * $l['can_rdm_max'] / $max_price, 2);
                $rdm_credit = round($credit['credit'] * $l['can_rdm_max'] / $max_price);

                $l['payment'] = bcsub($l['payment'], $rdm_num, 2);
                $l['credit']  = ['credit' => $rdm_credit, 'num' => $rdm_num];
                $add_num      = bcadd($add_num, $rdm_num, 2);
                $add_credit   = bcadd($add_credit, $rdm_credit, 2);
            }
        }

        return $datas;
    }

    /* 检查重复订单、小班课 */

    /**
     * 检查重复订单
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-27
     */
    public function checkOrderExist($product, $product_type, $section = 0)
    {
        // 学员已有课程
        if (in_array($product_type, [1, 2, 3, 4])) {
            $student = app(CourseStudent::class)->scope('mid')->where('course_id', $product)->whereRaw('expire_time is null OR expire_time > ' . time())->findOrEmpty();
            if (!$student->isEmpty()) throw new LogicException('存在已购买课程');
        }
        // 检测重复订单
        // $order_status = $this->orderStatus($product, $product_type, $section);
        // 条件
        $map = [
            ['user_id', '=', $this->uid],
            ['product_id', '=', $product],
            ['product_type_id', '=', $product_type],
            ['section_id', '=', $section],
        ];

        $order = app(POI::class)->where($map)->whereRaw('expire_time is null OR expire_time > ' . time())->order('order_no', 'DESC')->with(['order_status' => function ($query) {
            $query->whereIn('status', '10,20,30,40,80');
        }])->findOrEmpty();
        // 已消费
        if ($order->status) {
            $exTime = 0;
            // 已购买且在有效期内
            if ($order->status == 20 && in_array($product_type, [1, 2, 3, 4])) {
                $exTime = app(CourseStudent::class)->scope('mid')->where('course_id', $product)->whereNotNull('expire_time')->value('expire_time');
                $exTime = intval($exTime);
            }
            $paid = app(ExpenditureFlow::class)->where('order_sub_no', $order->order_sub_no)->whereUserId($order->user_id)->whereRelId($product)->where('create_time', '>', $exTime)->findOrEmpty();
            if (!$paid->isEmpty()) throw new LogicException('已购买，请等待后台处理');
        }

        if ($order->isEmpty()) return;
        if (in_array($order['status'], [10, 30, 40])) {
            if ($order['status'] == 10) {
                $data = app(PaymentOrderModel::class)->with(['redeem_credit_sub'])->findOrEmpty($order['order_no']);
                if ($data->isEmpty()) return;
                $data->status = 60;
                if (!$data->save()) throw new LogicException('订单已存在', '已有商品订单存在');
                // 处理积分退还
                if (count($data->redeem_credit_sub)) {
                    app(Credit::class)->returnOrderCredit($data);
                }
                // 处理卡券退还
                $coupon_ids = app(POIC::class)->alias('c')->join('payment_order_item i', 'i.order_sub_no=c.order_sub_no')->where('i.order_no', $order['order_no'])->group('coupon_id')->column('coupon_id');
                if (count($coupon_ids)) {
                    app(CouponUser::class)->returnOrderCoupon($order->user_id, implode(',', $coupon_ids));
                }
                // 处理活动券退还
                $ticket_ids = app(POIC::class)->alias('c')->join('payment_order_item i', 'i.order_sub_no=c.order_sub_no')->where('i.order_no', $order['order_no'])->group('coupon_id')->column('ticket_coupon_id');
                if (count($ticket_ids)) {
                    app(CouponUser::class)->returnOrderCoupon($order->user_id, implode(',', $ticket_ids), true);
                }
                return;
            }
            throw new LogicException('订单已存在', '已有商品订单存在');
        } else if (in_array($order['status'], [20, 80])) {
            //  && $order['expire_time'] > time()
            throw new LogicException('存在已购买课程');
        }
    }

    /**
     * 检测小班课购买人数限制
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date：   2020-09-08
     */
    public function checkSmallLiveLimit($course)
    {
        if ($course->course_type == 2 && $course->limit_buy_count) {
            $count = app(CourseStudent::class)->where('course_id', $course->id)->count();
            if ($count >= $course->limit_buy_count) throw new LogicException('已超出最大购买人数，请联系客服');
        }
    }

    /**
     * 订单状态
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-27
     */
    public function orderStatus($product_id, $product_type_id, $section_id)
    {
        // 条件
        $map = [
            ['user_id', '=', request()->mid],
            ['product_id', '=', $product_id],
            ['product_type_id', '=', $product_type_id],
            ['section_id', '=', $section_id],
        ];

        return app(POI::class)->where($map)->with(['order_status'])->selectOrFail();
    }

    /* 创建订单方法 */
    /**
     * 创建订单方法
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-27
     *
     * @param    [type]                      $datas [description]
     * @param    [type]                      $price [description]
     * @throws Exception
     */
    protected function createOrder($datas, $price)
    {
        $promotion = array_column($datas, 'promotion_type');
        // 主订单
        $save_order = [
            'order_no'    => app(SnowFlake::class)->createPD(),
            'user_id'     => $this->uid,
            'from'        => $this->from,
            'mhm_id'      => request()->user->mhm_id,
            'payment'     => $price,
            'status'      => $price ? '10' : (in_array(4, $promotion) ? '80' : '20'),
            'close_time'  => $this->close_time ?: null,
            'create_time' => time(),
            'update_time' => time(),
        ];
        $save_order['status'] == 20 && $save_order['payment_time'] = time();
        $order = $this::create($save_order);

        if ($order->isEmpty()) throw new LogicException('订单生成失败', '主订单生成失败');

        $save_list = $this->saveAllList($datas, $order->order_no);

        $order_item = app(POI::class)->saveAll($save_list['item']); // 批量生成子订单

        if (!empty($save_list['coupon'])) {
            // 卡券
            $order_coupon = app(POIC::class)->saveAll($save_list['coupon']);

            if ($order_coupon->isEmpty()) throw new LogicException('订单生成失败', '卡券生成失败');

            $coupon_ids = array_unique(array_column($save_list['coupon'], 'coupon_id'));
            $ticket_ids = array_unique(array_column($save_list['coupon'], 'ticket_coupon_id'));

            $coupon_ids = array_filter($coupon_ids, function ($v) {
                return $v;
            });
            $ticket_ids = array_filter($ticket_ids, function ($v) {
                return $v;
            });

            foreach ($ticket_ids as $ticket_id) {
                $coupon_use = app(CouponUser::class)->scope('mid')->where('ticket_id', $ticket_id)->findOrEmpty();
                // 非课程卡，状态为2，即使用到订单
                $coupon_use->status = $price ? 2 : 1;
                if (!$coupon_use->save()) throw new LogicException('订单生成失败', '卡券使用失败');
                // 订单需要支付
                $order->need_pay = $price ? 1 : 0;
            }
            foreach ($coupon_ids as $coupon_id) {
                $coupon_use = app(CouponUser::class)->scope('mid')->where('coupon_id', $coupon_id)->findOrEmpty();
                // 课程卡处理
                $coupon_type = app(Coupon::class)->where('id', $coupon_id)->value('coupon_type');
                if ($coupon_type == 3) {
                    // 只有单课程购买，才会使用课程卡
                    // 课程卡，卡券状态直接为1，即已使用
                    $coupon_use->status = 1;
                    if (!$coupon_use->save()) throw new LogicException('订单生成失败', '卡券使用失败');
                    // 课程卡，订单状态直接为20
                    $order->status = 20;
                    $order->save();
                    // 订单不需要支付
                    $order->need_pay = 0;
                    // 添加学员
                    $coupon_order_data = [
                        'order_sub_no' => $save_list['item'][0]['order_sub_no'],
                        'coupon_id'    => $coupon_id,
                    ];
                    $this->handleCourseCardCourse($datas[0]['course_id'], $coupon_order_data, $save_list['item'][0]['expire_time']);
                } else {
                    // 非课程卡，状态为2，即使用到订单
                    $coupon_use->status = $price ? 2 : 1;
                    if (!$coupon_use->save()) throw new LogicException('订单生成失败', '卡券使用失败');
                    // 订单需要支付
                    $order->need_pay = $price ? 1 : 0;
                }
            }
        } else {
            // 订单需要支付
            $order->need_pay = $price ? 1 : 0;
        }

        // 支付金额为0时，创建支付记录
        if (20 == $order->status) {
            app(Transaction::class)->addTransaction($order, 'lcnpay', true);
            $params = [];
            foreach ($order_item as $item) {
                // 下单时是否是会员
                $vip_user = app(VipUser::class)->where('user_id', $item->user_id)->where('expire_time', '>=', $item->create_time)->findOrEmpty();

                $from = $item->payment ? ($vip_user->isEmpty() ? 2 : 3) : ($vip_user->isEmpty() ? 4 : 5);

                $params[] = [
                    'user_id'     => $item->user_id,
                    'course_id'   => $item->product_id,
                    'from'        => $from, // 2:学员购买 3:会员购买
                    // 'create_time'   => $item->create_time
                    'expire_time' => $item->expire_time ?: null,
                ];
                // $stu = new CourseStudent;
                // $save = $stu->save($param);
                // if ( !$save ) throw new LogicException('操作失败');
            }
            if (count($params)) {
                $save = app(CourseStudent::class)->replace()->saveAll($params);
                if ($save->isEmpty()) throw new LogicException('操作失败');
            }
            // 拼团课程，支付金额为零时，修改团信息
        } else if (80 == $order->status) {

            foreach ($order_item as $item) {

                $user_id      = $item->user_id;
                $promotion_id = $item->promotion_id;

                $tuan = app(PT::class)->promotionId($promotion_id)->userId($user_id)->order('id DESC')->findOrEmpty();

                if (!$tuan->isEmpty()) {
                    $tuan->status = 1;
                    if (!$tuan->save()) throw new LogicException('操作失败');
                }

                $sql = app(PTD::class)->alias('d')->join('promotion_tuan t', "`t`.`id`=`d`.`tuan_id` AND `t`.`promotion_id`=$promotion_id AND `d`.`user_id`=$user_id AND d.delete_time is null")->field('d.*')->buildSql();

                $tuan_data = Db::query($sql);

                if ($tuan_data) {

                    $tuan_data = app(PTD::class)->findOrEmpty(current($tuan_data)['id']);
                    //
                    $tuan_data->status       = 1;
                    $tuan_data->order_sub_no = $item->order_sub_no;
                    if (!$tuan_data->save()) throw new LogicException('操作失败');
                    //
                    $tuan = app(PT::class)->findOrEmpty($tuan_data->tuan_id);
                    if ($tuan->join_num + 1 == $tuan->total_num) $tuan->status = 2;
                    $tuan->join_num += 1;
                    if (!$tuan->save()) throw new LogicException('操作失败');
                }
            }
        }
        return $order;
    }

    /* 处理免费课程 */
    public function handleFreeCourse($course)
    {
        $have = app(CourseStudent::class)->scope('mid')->where('course_id', $course->id)->findOrEmpty();
        // 不存在就添加
        if (!$have->isEmpty()) return;
        $expire = null;
        $term   = $course->term_time;
        $term && $expire = strlen($term . '') > 4 ? $term : time() + $term * 86400;
        $save = [
            'user_id'     => request()->mid,
            'course_id'   => $course->id,
            'from'        => $course->price == '0.00' ? 4 : 5,
            'expire_time' => $expire
        ];
        $add  = CourseStudent::create($save);
        if ($add->isEmpty()) throw new LogicException('订单生成失败');
        // 删除购物车对应的商品
        $cart = app(CourseCart::class)->scope('mid')->where('course_id', $course->id)->findOrEmpty();

        if ($cart->isEmpty()) return;
        if (!$cart->delete()) throw new LogicException('订单生成失败');
    }

    /**
     * @throws Exception
     */
    public function handleFreeCourse1($datas)
    {
        $saveAll = [];
        foreach ($datas as $data) {

            $have = app(CourseStudent::class)->scope('mid')->where('course_id', $data->id)->findOrEmpty();
            // 不存在就添加
            if ($have->isEmpty()) {
                $saveAll[] = [
                    'user_id'   => request()->mid,
                    'course_id' => $data->id,
                    'from'      => $data->price == '0.00' ? 4 : 5,
                ];
            }
        }

        if (count($saveAll)) {

            $free = app(CourseStudent::class)->saveAll($saveAll);

            if ($free->isEmpty()) throw new LogicException('订单生成失败');
        }
    }

    /* 处理免费课程之课程卡 */

    public function handleCourseCardCourse($course_id, $coupon_order_data, $expire_time = 0)
    {
        // 学员表
        $have = app(CourseStudent::class)->scope('mid')->where('course_id', $course_id)->findOrEmpty();
        // 不存在就添加
        if ($have->isEmpty()) {
            $create = [
                'user_id'   => request()->mid,
                'course_id' => $course_id,
                'from'      => 6,
            ];
            $expire_time && $create['expire_time'] = $expire_time;
            $free = CourseStudent::create($create);

            if ($free->isEmpty()) throw new LogicException('订单生成失败');
            // 卡券使用到订单
            $coupon_order = POIC::create($coupon_order_data);
            if ($coupon_order->isEmpty()) throw new LogicException('订单生成失败');
        }
    }

    /* 购物车购买 */

    /**
     * 购物车订单结算页面
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-21
     */
    public function orderFetchCart($param): array
    {
        // 验证数据
        $this->getValidate()->scene('order_cart')->failException()->check($param);
        $course_ids = trim($param['course_ids'], ',');
        // 课程
        $datas  = [];
        $school = app(Course::class)->with(['school'])->where('id', 'IN', $course_ids)->field('mhm_id')->group('mhm_id')->select();
        // 定义是否存在课程可以抵扣积分
        $credit_redeem = 0;
        // 定义可以抵扣积分课程的价格总和
        $rdm_price = 0;
        // 订单价格
        $order_price = 0;

        foreach ($school as $v) {
            $mhm_id              = $v['mhm_id'];
            $data['mhm_id']      = $mhm_id;
            $data['school_name'] = $v['school_name'];
            // 课程
            $list = app(Course::class)->field($this->orderField)->with(['cover_url'])->withCount(['section_count' => 'section_count'])->where('id', 'IN', $course_ids)->where('mhm_id', $mhm_id)->selectOrFail()->append(['course_type_text', 'user_price']);

            $data['course_list'] = $list;
            // 课程总价
            $total_price         = round(array_sum(array_column($list->toArray(), 'user_price')), 2);
            $data['total_price'] = $total_price;
            // 订单总价
            $order_price = bcadd($order_price, $total_price, 2);
            // 机构当前可用最优卡券
            $best_coupon         = app(CouponUser::class)->getUserBestCouponByTotalPrice($total_price, $mhm_id);
            $data['best_coupon'] = $best_coupon;
            if ($best_coupon && count((array)$best_coupon)) {
                $order_price = bcsub($order_price, $best_coupon->price, 2);
            }
            //
            $datas[] = $data;
            //
            foreach ($list as $course) {
                $course->user_course_card = app(Coupon::class)->userHasDerivedCourseCard($course->id);
                if ($course->course_type == 4) {
                    $course->section_count = app(Classes::class)->getClassesSectionCount($course->id);
                }
            }
            // 计算积分抵扣
            $course_num  = count($list);
            $list_arr    = $list->toArray();
            $can_rdm_num = array_sum((array_column($list_arr, 'credit_redeem')));
            $can_rdm_num && $credit_redeem = 1;

            $_list = ['rdm' => [], 'not' => []];
            foreach ($list as $c) {
                if ($c['credit_redeem']) $_list['rdm'][] = $c;
                if (!$c['credit_redeem']) $_list['not'][] = $c;
            }

            if (!count($_list['rdm'])) continue;
            // 不可抵扣积分的课程的总价
            $not_price = array_sum(array_column($_list['not'], 'user_price'));
            // 可抵扣积分的课程的总价
            $_total = array_sum((array_column($_list['rdm'], 'user_price')));
            // 可抵扣课程最终抵扣价格
            foreach ($_list['rdm'] as $l) {
                $uprice      = $l->user_price;
                $can_rdm_max = 0;
                $crp         = bcdiv($l->credit_redeem_percent, 100, 2);
                if (!empty($best_coupon) && 1 == $best_coupon->coupon_type) {
                    if ($can_rdm_num == $course_num) {
                        // 优惠券：2
                        $can_rdm_max = bcmul(($uprice - $uprice / $total_price * $best_coupon->price), $crp, 2);
                    } else if (0 != $can_rdm_num) {
                        // 优惠券：1
                        // 比较是否可以完全抵扣优惠券
                        $_price      = $not_price > $best_coupon->price ? 0 : round($best_coupon->price - $not_price, 2);
                        $up          = $uprice - $_price * $uprice / $_total;
                        $can_rdm_max = bcmul($up, $crp, 2);
                    }
                } else if (!empty($best_coupon) && 2 == $best_coupon->coupon_type) {
                    // 优惠后价格
                    $can_rdm_max = bcmul(($uprice * $best_coupon->discount / 10), $crp, 2);
                } else {
                    // 积分抵扣价格
                    $can_rdm_max = bcmul($uprice, $crp, 2);
                }
                $rdm_price += $can_rdm_max;
            }
        }

        // 积分抵扣数组
        $credit_arr = $credit_redeem ? app(Credit::class)->getUserCreditRedeemArr(intval($rdm_price), $order_price) : [];

        return ['cart' => $datas, 'credit' => $credit_arr];
    }

    /**
     * 切换卡券更新积分选择
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-08-31
     *
     * @param  [type] $param [description]
     */
    public function orderCartCredit($param): array
    {
        /** 规则
         * 优惠券：1、课程部分可以抵扣积分时，优惠券优先使用不能抵扣的课程，再计算积分抵扣
         * 优惠券：2、课程全部可以抵扣积分时，优惠券和积分统一按比例分配
         * 优惠券：3、课程全部不可以抵扣积分时，优惠券按比例分配
         * 打折卡：全部折扣后再计算积分抵扣
         */
        // 参数
        $course = trim($param['course'] ?? '', ',');
        $coupon = trim($param['coupon'] ?? '', ',');
        $ticket = trim($param['ticket'] ?? '', ',');
        if (!$course) throw new LogicException('参数错误');
        // 课程ID数组
        $ids = explode(',', $course);
        array_walk($ids, function (&$id) {
            $id = $id * 1;
        });
        //
        $rdm_price   = 0;
        $order_price = 0;
        // 无卡券和活动券时
        if (!$coupon && !$ticket) {
            $list = app(Course::class)->field($this->couponField)->where('id', 'IN', $course)->selectOrFail();
            foreach ($list as $l) {
                $order_price += $l->user_price;
                // 优惠后价格
                $can_rdm_max = $l->credit_redeem ? bcmul($l->user_price, bcdiv($l->credit_redeem_percent, 100, 2), 2) : 0;
                $rdm_price   += $can_rdm_max;
            }
            // 积分抵扣
            return app(Credit::class)->getUserCreditRedeemArr(intval($rdm_price), $order_price);
        }
        // 使用卡券的课程
        $field   = 'coupon_type,maxprice,price,discount,mhm_id';
        $coupons = $coupon ? app(Coupon::class)->field($field)->with(['user_has'])->whereIn('id', $coupon)->selectOrFail()->append([])->toArray() : [];
        $tickets = $ticket ? app(TicketCoupon::class)->field($field)->with(['user_has'])->whereIn('id', $ticket)->selectOrFail()->toArray() : [];
        $coupons = array_merge($coupons, $tickets);
        // halt($course, $coupons);
        foreach ($coupons as $c) {
            //
            $list = app(Course::class)->field($this->couponField)->where('id', 'IN', $course)->whereMhmId($c['mhm_id'])->select();
            if ($list->isEmpty()) throw new LogicException('卡券不满足课程使用');
            $_ids        = array_column($list->toArray(), 'id');
            $ids         = array_diff($ids, $_ids);
            $list_arr    = $list->toArray();
            $can_rdm_num = array_sum((array_column($list_arr, 'credit_redeem')));
            $total_price = array_sum((array_column($list_arr, 'user_price')));
            // 卡券类型
            if (1 == $c['coupon_type']) {
                $course_num = count($list);
                if ($total_price < $c['maxprice']) throw new LogicException('订单价格不满足卡券使用条件');
                $order_price += ($total_price - $c['price']);

                // if (0 == $can_rdm_num) {
                //     // 优惠券：3
                // } else
                if ($can_rdm_num == $course_num) {
                    // 优惠券：2
                    foreach ($list as $l) {
                        // 优惠后价格
                        $crp         = bcdiv($l->credit_redeem_percent, 100, 2);
                        $can_rdm_max = bcmul(($l->user_price - $l->user_price / $total_price * $c['price']), $crp, 2);
                        $rdm_price   = bcadd($rdm_price, $can_rdm_max, 2);
                    }
                } else {
                    // 优惠券：1
                    $_list = [];
                    foreach ($list as $v) {
                        $v['credit_redeem'] && $_list['rdm'][] = $v;
                        !$v['credit_redeem'] && $_list['not'][] = $v;
                    }
                    // 不可抵扣积分的课程的总价
                    $not_price = isset($_list['not']) ? array_sum(array_column($_list['not'], 'user_price')) : 0;
                    // 比较是否可以完全抵扣优惠券
                    $_price = $not_price > $c['price'] ? 0 : round($c['price'] - $not_price, 2);
                    if (isset($_list['rdm'])) {
                        $_total = array_sum((array_column($_list['rdm'], 'user_price')));

                        foreach ($_list['rdm'] as $r) {
                            $up = $r->user_price;
                            // $pe = $up * $r->credit_redeem_percent / 100;
                            $up = $up - $_price * $up / $_total;
                            // $rdm_price  += min($up, $pe);
                            $can_rdm_max = bcmul($up, bcdiv($r->credit_redeem_percent, 100, 2), 2);
                            $rdm_price   = bcadd($rdm_price, $can_rdm_max, 2);
                        }
                    }
                }
            } else if (2 == $c['coupon_type']) {
                foreach ($list as $l) {
                    // 优惠后价格
                    $crp         = bcdiv($l->credit_redeem_percent, 100, 2);
                    $can_rdm_max = $l->credit_redeem ? bcmul(bcmul($l->user_price, bcdiv($c['discount'], 10, 3), 2), $crp, 2) : 0;
                    $rdm_price   = bcadd($rdm_price, $can_rdm_max, 2);
                }
                $order_price += $total_price * $c['discount'] / 10;
            }
        }
        // 未使用卡券课程
        if (count($ids)) {
            $list = app(Course::class)->field($this->couponField)->where('id', 'IN', $ids)->selectOrFail();
            foreach ($list as $v) {
                $order_price += $v->user_price;
                if ($v->credit_redeem) {
                    // 优惠后价格
                    $can_rdm_max = bcmul($v->user_price, bcdiv($v->credit_redeem_percent, 100, 2), 2);
                    $rdm_price   = bcadd($rdm_price, $can_rdm_max, 2);
                }
            }
        }
        // 积分抵扣
        return app(Credit::class)->getUserCreditRedeemArr(intval($rdm_price), $order_price);
    }

    /**
     * 创建购物车订单
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-24
     *
     * @throws Exception
     */
    public function orderCreateCart($param)
    {
        // 事件检测 用户--课程--卡券对应关系是否正确，及卡券使用情况【一个机构仅限一种优惠方式】
        // 【用户是否具有此卡、满减情况、课程卡对应、折扣金额情况】
        // 验证数据
        $this->getValidate()->scene('order_cart_create')->failException()->check($param);
        // 参数
        $course = is_array($param['course']) ? $param['course'] : json_decode($param['course'], true);
        $credit = $param['credit'] ?? [];
        $credit = is_array($credit) ? $credit : json_decode($credit, true);

        // 数据 -- 根据机构分别查询课程信息
        $datas  = [];
        $id_str = '';
        // 定义是否存在课程可以抵扣积分
        // 定义可以抵扣积分课程的价格总和
        //
        $this->startTrans();
        try {
            foreach ($course as $v) {
                $course_ids = trim($v['course_ids'], ',');
                $id_str     .= $course_ids . ',';
                // 课程列表信息
                $list = app(Course::class)->where('id', 'IN', $course_ids)->field($this->orderField)->select();
                // 重复订单、小班课、免费课处理
                $course_num = count($list);
                foreach ($list as $k => $l) {
                    $l->final_price = $l->user_price;
                    // 检查重复订单
                    $this->checkOrderExist($l->id, $l->course_type);
                    // 小班课人数限制检测
                    $this->checkSmallLiveLimit($l);
                    // 剔除免费课程 - 单课程一般不会走这里，此处作逻辑的缜密性
                    if ($l->user_price == 0) {
                        $this->handleFreeCourse($l);
                        $course_num -= 1;
                        if (!$course_num) throw new LogicException('课程不需要购买');
                        unset($list[$k]);
                    }
                }
                // 使用卡券
                $coupon = [];
                if (isset($v['coupon']) && $v['coupon']) {
                    $coupon = app(Coupon::class)->with(['user_has'])->findOrEmpty($v['coupon'])->append([]);
                    if ($coupon->isEmpty() || !$coupon->user_has) throw new LogicException('卡券异常，请更换使用');
                    $coupon = $coupon->toArray();
                } else if (isset($v['ticket']) && $v['ticket']) {
                    $coupon = app(TicketCoupon::class)->with(['user_has'])->findOrEmpty($v['ticket']);
                    if ($coupon->isEmpty() || !$coupon->user_has) throw new LogicException('卡券异常，请更换使用.');
                    $coupon = $coupon->toArray();
                }
                // 计算价格后的数据列表
                $datas = $this->calculatePrice($list, $coupon, $datas);
            }
            // 检查积分抵扣是否符合
            $datas = $this->checkCreditRedeem($datas, $credit);
            // 检查价格
            $course_price = round(array_sum(array_column($datas, 'payment')), 2);
            // 生成订单
            $order = $this->createOrder($datas, $course_price);
            // 抵扣积分
            if (count($credit) && isset($credit['credit']) && $credit['credit']) {
                app(Credit::class)->redeemCredit(intval($credit['credit']), $order->order_no);
            }
            // 删除购物车对应的商品
            $cart = app(CourseCart::class)->scope('mid')->where('course_id', 'IN', trim($id_str, ','))->select();
            if (!$cart->delete()) throw new LogicException('订单提交失败.');
            $this->commit();
            return $order;
        } catch (LogicException $e) {
            $this->rollback();
            throw new LogicException($e->getMessage());
        } catch (Exception $e) {
            $this->rollback();
            throw $e;
        }
    }

    /**
     * 计算价格 - 根据商品及卡券计算价格
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     *
     * @param       $course [商品数据]
     * @param       $coupon [卡券数据]
     * @param array $datas  [返回数据]
     * @return   array      $datas  [整合后数据]
     */
    protected function calculatePrice($course, $coupon, array $datas = []): array
    {
        $courseArr  = is_array($course) ? $course : $course->toArray();
        $courseNum  = count($courseArr);
        $canRdmNum  = array_sum((array_column($courseArr, 'credit_redeem')));
        $totalPrice = round(array_sum(array_column($courseArr, 'final_price')), 2);

        /* 活动和卡券不能同时使用 */
        if (!count($coupon)) {
            foreach ($course as $v) {
                $datas[] = [
                    'course_id'      => $v->id,
                    'course_type'    => $v->course_type,
                    'mhm_id'         => $v->mhm_id,
                    'promotion_id'   => $v['promotion'] ?? 0,
                    'promotion_type' => $v['promotion_type'] ?? 0,
                    'original_price' => $v->price,
                    'coupon_id'      => 0,
                    'ticket_id'      => 0,
                    'discount'       => 0,
                    'payment'        => $v['final_price'],
                    'credit_redeem'  => $v['credit_redeem'],
                    'cdt_rdm_per'    => $v['credit_redeem_percent'],
                    'term_time'      => intval($v->term_time),
                ];
            }
            return $datas;
        }
        $discount = 0;
        // 计算总共优惠的价格
        switch ($coupon['coupon_type']) {
            case 1:
                if ($totalPrice < $coupon['maxprice']) throw new LogicException('订单价格不满足卡券使用条件');
                $discount = $coupon['price'];
                break;
            case 2:
                $discount = bcsub($totalPrice, bcmul(bcdiv($coupon['discount'], 10, 3), $totalPrice, 2), 2);
                break;
            case 3:
                $discount = $totalPrice;
                break;
        }

        /** 规则
         * 优惠券：1、课程部分可以抵扣积分时，优惠券优先使用不能抵扣的课程，再计算积分抵扣
         * 优惠券：2、课程全部可以抵扣积分时，优惠券和积分统一按比例分配
         * 优惠券：3、课程全部不可以抵扣积分时，优惠券按比例分配
         * 打折卡：全部折扣后再计算积分抵扣
         */
        // 优惠券：1时
        if (1 == $coupon['coupon_type'] && 0 != $canRdmNum && $canRdmNum != $courseNum) {
            $_list = [];
            foreach ($course as $v) {
                $v['credit_redeem'] && $_list['rdm'][] = $v;
                !$v['credit_redeem'] && $_list['not'][] = $v;
            }
            // 不可抵扣积分的课程的总价
            $not_price = array_sum(array_column($_list['not'], 'user_price'));
            if ($not_price < $discount) {
                $d1 = $not_price;
                $d2 = bcsub($discount, $not_price, 2);
            } else {
                $d1 = $discount;
                $d2 = 0;
            }
            $datas = $this->_calculatePrice($_list['not'], $coupon['id'], $d1, $datas, isset($coupon['ticket_id']));
            return $this->_calculatePrice($_list['rdm'], $coupon['id'], $d2, $datas, isset($coupon['ticket_id']));
        }

        return $this->_calculatePrice($course, $coupon['id'], $discount, $datas, isset($coupon['ticket_id']));
    }

    private function _calculatePrice($course, $coupon_id, $discount, $datas = [], $ticket = false): array
    {
        $discs       = 0;
        $total_price = round(array_sum(array_column(is_array($course) ? $course : $course->toArray(), 'final_price')), 2);

        foreach ($course as $k => $v) {
            $data['course_id']      = $v->id;
            $data['course_type']    = $v->course_type;
            $data['mhm_id']         = $v->mhm_id;
            $data['original_price'] = $v->price;
            $data['coupon_id']      = $ticket ? 0 : $coupon_id;
            $data['ticket_id']      = $ticket ? $coupon_id : 0;
            $data['credit_redeem']  = $v->credit_redeem;
            $data['cdt_rdm_per']    = $v->credit_redeem_percent;

            if (count($course) != $k + 1) {
                $disc = round($v->final_price / $total_price * $discount, 2);
                // $cred             = round($v->final_price / $total_price * $v['credit']['num'], 2);
                $payment          = bcsub($v->final_price, $disc, 2);
                $discs            = bcadd($discs, $disc, 2);
                $data['discount'] = $disc;
                $data['payment']  = $payment;
            } else {
                $data['discount'] = bcsub($discount, $discs, 2);
                $data['payment']  = bcsub($v->final_price, $data['discount'], 2);
            }

            $data['term_time'] = intval($v->term_time);
            $datas[]           = $data;
        }

        return $datas;
    }

    /**
     * 生成订单数据 - sql数据
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     */
    protected function saveAllList($data, $PD): array
    {
        $item     = [];
        $coupon   = [];
        $ext_data = [];
        // 上级用户树
        $superiors = app(User::class)->getSuperiors();
        $superiors['primary'] && $ext_data['primary'] = $superiors['primary'];
        $superiors['secondary'] && $ext_data['secondary'] = $superiors['secondary'];
        // 分享人
        $share_code = Request::header('E-SHARE-CODE');
        if ($share_code) {
            $share_data = app(ShareCode::class)->whereCode($share_code)->findOrEmpty();
            if (!$share_data->isEmpty()) {
                $param = $share_data->param;
            }
        }
        // 挂载机构
        # code...
        // 数据
        foreach ($data as $v) {
            if (isset($param) && $param['id'] == $v['course_id'] && $param['type'] == 1 && $param['mid'] != $this->uid) $ext_data['share'] = $param['mid'];
            $PI     = app(SnowFlake::class)->createPI();
            $expire = null;
            $v['term_time'] && $expire = strlen($v['term_time'] . '') > 4 ? $v['term_time'] : time() + $v['term_time'] * 86400;
            $save = [
                'order_no'        => $PD,
                'order_sub_no'    => $PI,
                'user_id'         => $this->uid,
                'from'            => $this->from,
                'mhm_id'          => $v['mhm_id'],
                'product_id'      => $v['course_id'],
                'product_type_id' => Course::getProductIdByCourseType($v['course_type']),
                'promotion_id'    => $v['promotion_id'] ?? 0,
                'payment'         => $v['payment'],
                'original_price'  => $v['original_price'],
                'expire_time'     => $expire,
                'credit'          => $v['credit'] ?? '',
            ];
            if (count($ext_data)) $save['ext_data'] = $ext_data;
            $item[] = $save;
            if ($v['coupon_id'] || $v['ticket_id']) {
                $coupon[] = [
                    'order_sub_no'     => $PI,
                    'coupon_id'        => $v['coupon_id'],
                    'ticket_coupon_id' => $v['ticket_id'],
                ];
            }
        }
        return ['item' => $item, 'coupon' => $coupon];
    }

    /* 课时直接购买 */

    /**
     * 课时直接购买订单页
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     */
    public function orderSectionFetch($param)
    {
        // 验证数据
        $this->getValidate()->scene('section')->failException()->check($param);

        // 参数
        $section_id = intval($param['section_id']);

        $section = app(CourseSection::class)
            ->field('id,title,course_type,course_id,is_last,price,course_data_id')
            ->where('is_last', 1)
            ->with(['course_info'])
            ->findOrFail($section_id)
            ->hidden(['course_info']);

        // 非单卖课程禁止购买
        if (!$section->course_info->solo) throw new LogicException('课程禁止购买');

        $section->product_key = ProductType::getProductKeyById(Course::getProductIdByCourseType($section->course_type));
        $section->user_price  = $section->price;
        $section->term_time   = $section->course_info->term_time;

        if ($section->course_type == 1) {
            $section_data            = app(CourseSection::class)->parseCourseHour($section);
            $section->data_type      = $section_data->data_type;
            $section->data_type_text = $section_data->data_type_text;
            // } else if ($section->course_type == 2) {
            // $section_data = app(CourseSection::class)->parseCourseHour($section);
        }

        // 积分抵扣数组
        $section->credit_arr = [];
        if ($section->course_info->credit_redeem) {
            // 课程抵扣比例
            $percent   = $section->course_info->credit_redeem_percent;
            $max_price = intval(bcdiv(bcmul(strval($section->user_price), strval($percent), 2), '100'));

            $section->credit_arr = app(Credit::class)->getUserCreditRedeemArr($max_price, $section->user_price);
        }

        return $section;
    }

    /**
     * 创建课时订单
     * Author   亓官雨树<lucky.max@foxmail.com>
     * Date 2020-04-26
     */
    public function createSectionOrder($param)
    {
        // 验证数据
        $this->getValidate()->scene('section')->failException()->check($param);

        // 参数
        $section_id = $param['section_id'];
        $credit     = $param['credit'] ?? [];
        $credit     = is_array($credit) ? $credit : json_decode($credit, true);
        $credit_use = false;

        // 检查课时
        $sec    = app(CourseSection::class)->LastSec($section_id)->with(['course_info'])->findOrFail();
        $price  = $sec->price;
        $course = $sec->course_info;
        $expire = null;
        $term   = $course->term_time;
        $term && $expire = strlen($term . '') > 4 ? $term : time() + $term * 86400;

        $this->startTrans();
        try {
            // 检查重复订单
            $this->checkOrderExist($sec->course_id, 1, $section_id);
            // 检查积分抵扣是否符合
            if (count($credit) && isset($credit['credit']) && isset($credit['num']) && $course->credit_redeem) {
                // 课程最大抵扣金额
                $max_price = intval(round($price * $course->credit_redeem_percent) / 100);
                // 积分抵扣实例
                $redeem = new CreditRedeem(request()->user_id, $max_price);
                // 未配置积分抵扣
                if (!$redeem->hasRedeemRatio()) throw new LogicException('积分抵扣参数错误.');
                // 抵扣金额超限
                $max_redeem_num = $redeem->getMaxRedeemNum();

                if ($credit['num'] > $max_redeem_num) {
                    throw new LogicException('积分抵扣参数错误..');
                }
                if (!$redeem->isCreditMatchNum($credit)) {
                    throw new LogicException('积分抵扣参数错误...');
                }
                $price      -= $credit['num'];
                $credit_use = true;
            }
            // 主订单
            $order = $this::create([
                'order_no'    => app(SnowFlake::class)->createPD(),
                'user_id'     => $this->uid,
                'from'        => $this->from,
                'mhm_id'      => request()->user->mhm_id,
                'payment'     => $price,
                'status'      => $price ? '10' : '20',
                'create_time' => time(),
                'update_time' => time(),
            ]);
            if ($order->isEmpty()) throw new LogicException('订单生成失败');

            // 子订单
            $order_item = POI::create([
                'order_no'        => $order->order_no,
                'order_sub_no'    => app(SnowFlake::class)->createPI(),
                'user_id'         => $this->uid,
                'from'            => $this->from,
                'mhm_id'          => $sec->course_info->mhm_id,
                'product_id'      => $sec->course_info->id,
                'product_type_id' => Course::getProductIdByCourseType($sec->course_type),
                'payment'         => $price,
                'original_price'  => $price,
                'section_id'      => $section_id,
                'credit'          => $credit_use ? $credit : '',
                'expire_time'     => $expire
            ]);

            if ($order_item->isEmpty()) throw new LogicException('订单生成失败');
            // 积分抵扣
            $credit_use && app(Credit::class)->redeemCredit($credit['credit'], $order->order_no);

            if (20 == $order->status) {
                app(Transaction::class)->addTransaction($order, 'lcnpay', true);
            }

            $this->commit();
        } catch (LogicException $e) {
            $this->rollback();
            throw new LogicException($e->getMessage());
        }
        //
        $order->need_pay = $order->status == 20 ? 0 : 1;
        return $order;
    }

    public function yieldData($number): Generator
    {
        for ($i = 0; $i < $number; $i++) {
            $max = app(POI::class)->max('product_id');
            yield app(Course::class)->where('id', '>', $max)->limit(700)->column('id');
        }
    }

    public function createFalseOrder(): Json
    {
        ini_set('memory_limit', '1024M');
        set_time_limit(0);

        $result = $this->yieldData(1000);
        foreach ($result as $ids) {
            foreach ($ids as $v) {
                $PD = app(SnowFlake::class)->createPD();
                // 主订单
                $order = $this::create([
                    'order_no'    => $PD,
                    'user_id'     => 666,
                    'from'        => 'pc',
                    'mhm_id'      => 1,
                    'payment'     => 100,
                    'status'      => 20,
                    'close_time'  => null,
                    'create_time' => time(),
                    'update_time' => time(),
                ]);
                if ($order->isEmpty()) continue;

                // 子订单
                POI::create([
                    'order_no'        => $PD,
                    'order_sub_no'    => app(SnowFlake::class)->createPI(),
                    'user_id'         => 666,
                    'from'            => 'pc',
                    'mhm_id'          => 1,
                    'product_id'      => $v,
                    'product_type_id' => 1,
                    'payment'         => 100,
                    'original_price'  => 100,
                    'section_id'      => 0,
                    'credit'          => null,
                    'create_time'     => time(),
                    'update_time'     => time(),
                ]);
            }
        }

        return json(['true' => 1]);
    }

}
